﻿using System;
using System.Collections.Generic;
using Microsoft.Office.Interop.Word;
using Rectangle = System.Drawing.Rectangle;
using TestCenter.Classes;
using ManagedWinapi.Accessibility;

namespace TestCenter.Office
{
    class WordApplication : IOfficeApplication
    {
        private const string Caption = "Microsoft Word - Application";

        string IOfficeApplication.Caption
        {
            get { return Caption; }
        }

        private Application _app;
        private bool _isDisposed;
        private Rectangle _region;
        private AccessibleEventListener _listener;
        private Dictionary<String, int> _time;

        public IntPtr Handle { get; private set; }
        public Rectangle Region
        {
            get { return _region; }
            set { _region = value; Resize(); }
        }

        private void Resize()
        {
            WinApi.SetWindowPos(Handle, IntPtr.Zero, _region.X, _region.Y,
                _region.Width, _region.Height, 0);
        }

        public void Load()
        {
            Init();
        }

        private void SetupListener()
        {
            uint processId;
            uint threadId = WinApi.GetWindowThreadProcessId(Handle, out processId);

            _listener = new AccessibleEventListener
                            {
                                Enabled = false,
                                MaximalEventType = AccessibleEventType.EVENT_MAX,
                                MinimalEventType = AccessibleEventType.EVENT_MIN,
                                ThreadId = threadId,
                                ProcessId = processId
                            };
            _listener.EventOccurred += ListenerOnEventOccurred;

            _time = new Dictionary<string, int>();
        }

        private void ListenerOnEventOccurred(object sender, AccessibleEventArgs e)
        {
            try
            {
                if (e.EventType == AccessibleEventType.EVENT_OBJECT_LOCATIONCHANGE
                    && e.HWnd == IntPtr.Zero
                    && e.ObjectID == (uint)AccessibleObjectID.OBJID_CURSOR) return;

                if (e.AccessibleObject == null) return;

                var s = "";
                var obj = e.AccessibleObject;

                int lastTime;
                _time.TryGetValue(obj.Name, out lastTime);

                switch (e.EventType)
                {
                    case AccessibleEventType.EVENT_OBJECT_VALUECHANGE:
                        if (obj.StateString != "None")
                            break;
                        if (lastTime == 0 || e.Time - lastTime > 200)
                        {
                            s = "Change " + obj.Name + " to " + obj.Value;
                            _time[obj.Name] = (int)e.Time;
                        }
                        break;
                    case AccessibleEventType.EVENT_OBJECT_STATECHANGE:
                        switch (obj.RoleString)
                        {
                            case "push button":
                            case "split button":
                            case "check box":
                                if (obj.StateString.Contains("pressed") == false)
                                    break;

                                if (lastTime == 0 || e.Time - lastTime > 200)
                                {
                                    s = "Click " + obj.RoleString + " " + obj.Name;
                                    _time[obj.Name] = (int)e.Time;
                                }
                                break;
                            default:
                                //s = obj.RoleString + " " + obj.Name;
                                break;
                        }
                        break;
                    case AccessibleEventType.EVENT_OBJECT_SELECTION:
                        s = "Select " + obj.Name + " " + obj.RoleString + " " + obj.StateString;
                        break;
                    default:
                        //s = e.EventType.ToString();
                        break;
                }

                if (s.Length > 0) Event(s, null);
            }
            catch
            {

            }
        }

        public event EventHandler Event;

        private void OnQuit()
        {
            _isDisposed = true;
            DisableListener();
        }

        private void Init()
        {
            _app = new Application { Caption = Caption };
            Handle = WinApi.FindWindowByCaption(IntPtr.Zero, _app.Caption);

            var wl = WinApi.GetWindowLong(Handle, WinApi.GWL_STYLE);
            wl = (int)(wl & ~(WinApi.WS_SIZEBOX | WinApi.WS_MAXIMIZEBOX));
            WinApi.SetWindowLong(Handle, WinApi.GWL_STYLE, wl);

            _app.Visible = true;
            _isDisposed = false;

            ((ApplicationEvents4_Event)_app).Quit += OnQuit;
            _app.WindowSelectionChange += AppOnWindowSelectionChange;

            SetupListener();
        }

        private void AppOnWindowSelectionChange(Selection sel)
        {
            var s = "Select text: " + _app.Selection.Text;
            Event(s, null);
        }

        public void Quit()
        {
            if (_app == null || _isDisposed) return;
            DisableListener();
            _app.Quit(WdSaveOptions.wdDoNotSaveChanges);
            _app = null;
        }

        public void LoadDocument(string fileName)
        {
            if (_isDisposed) Init();
            CloseAllDocuments();
            _app.Documents.Open(fileName);
        }

        public void CloseAllDocuments()
        {
            if (_isDisposed) Init();
            while (_app.Documents.Count > 0)
            {
                _app.Documents.Close(WdSaveOptions.wdDoNotSaveChanges);
            }
        }

        public void EnableListener()
        {
            _listener.Enabled = true;
        }

        public void DisableListener()
        {
            _listener.Enabled = false;
        }
    }
}
